#coding=utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import logging, base64
from google.appengine.api import memcache, urlfetch
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.runtime import apiproxy_errors
from google.appengine.api.labs import taskqueue
import wsgiref.handlers

import transform_content

from ad import insert_ad
from utility import uri_b64decode
MAX_CONTENT_SIZE = 100 ** 6
EXPIRATION_DELTA_SECONDS = 60*2
IGNORE_HEADERS = frozenset([
  'set-cookie',
  'expires',
  'cache-control',

  # Ignore hop-by-hop headers
  'connection',
  'keep-alive',
  'proxy-authenticate',
  'proxy-authorization',
  'te',
  'trailers',
  'transfer-encoding',
  'upgrade',
])

TRANSFORMED_CONTENT_TYPES = frozenset([
  "text/html",
  "text/css",
])
################################################################################

def adjust_headers(headers):
  #logging.debug(str(headers))
  adjusted_headers = {}
  for key, value in headers.iteritems():
    adjusted_key = key.lower()
    if adjusted_key not in IGNORE_HEADERS:
        adjusted_headers[adjusted_key] = value
  
  #logging.debug(str(headers))
  return adjusted_headers
################################################################################

class MirroredContent(object):
  def __init__(self, url, headers, data):
    self.headers = headers
    self.data = data
    self.url = url
       
class MirrorHandler(webapp.RequestHandler):
  def get(self, encoded_url):
    logging.debug('User-Agent = "%s", Referrer = "%s"',
                  self.request.user_agent,
                  self.request.referer)
    '''
    content = memcache.get(encoded_url)
    if content:
      for key, value in content.headers.iteritems():
        self.response.headers[key] = value
      self.response.out.write(content.data)
   
    else:
    '''
    url = uri_b64decode(encoded_url)
  
    http_url = 'http://' + url
    logging.debug("Fetching '%s'", http_url)
    
    try:
      response = urlfetch.fetch(http_url)
    except (urlfetch.Error, apiproxy_errors.Error):
      logging.exception("Could not fetch URL")
      return self.error(404)
    logging.debug("Fetched '%s'", http_url)
    
    data = response.content
    headers = response.headers
    
    page_content_type = headers.get("content-type", "")
    for content_type in TRANSFORMED_CONTENT_TYPES:
      # Startswith() because there could be a 'charset=UTF-8' in the header.
      if page_content_type.startswith(content_type):
        data = transform_content.TransformContent(http_url, data)
        break

    # If the transformed content is over 1MB, truncate it (yikes!)
    if len(data) > MAX_CONTENT_SIZE:
      logging.warning('Content is over 1MB; truncating')
      data = data[:MAX_CONTENT_SIZE]
    
    headers = adjust_headers(headers)
    '''
    content = MirroredContent(url, headers, data)
    if not memcache.add(encoded_url, content, time=EXPIRATION_DELTA_SECONDS):
      logging.error('memcache add failed: encoded_url = "%s", '
                    'original_url = "%s"', encoded_url, http_url)
    logging.debug('New content added into memcache.')
    '''
    for key, value in headers.iteritems():
      self.response.headers[key] = value
    self.response.out.write(data)
    
  def post(self, encoded_url):
    url = uri_b64decode(encoded_url)
    http_url = 'http://' + url
    
    # Log the user-agent and referrer, to see who is linking to us.
    logging.debug('post!')
    logging.debug('User-Agent = "%s", Referrer = "%s"',
                  self.request.user_agent,
                  self.request.referer)
    logging.debug('url = "%s"', http_url)
    
    post_data = dict(self.request.POST)

    try:
      response = urlfetch.fetch(http_url, payload=post_data, method='POST')
    except (urlfetch.Error, apiproxy_errors.Error):
      logging.exception("Could not fetch URL")
      return self.error(404)
    
    data = response.content
    headers = response.headers
    
    page_content_type = headers.get("content-type", "")
    for content_type in TRANSFORMED_CONTENT_TYPES:
      # Startswith() because there could be a 'charset=UTF-8' in the header.
      if page_content_type.startswith(content_type):
        data = transform_content.TransformContent(http_url, data)
        break

    # If the transformed content is over 1MB, truncate it (yikes!)
    if len(data) > MAX_CONTENT_SIZE:
      logging.warning('Content is over 1MB; truncating')
      data = data[:MAX_CONTENT_SIZE]
    
    headers = adjust_headers(headers)
    
    for key, value in headers.iteritems():
      self.response.headers[key] = value
    self.response.out.write(data)
    
app = webapp.WSGIApplication([
  (r"/([^/]+).*", MirrorHandler),

], debug=True)

def main():
  wsgiref.handlers.CGIHandler().run(app)


if __name__ == "__main__":
  main()
